/* Copyright (c) 2023 Renmin University of China
RMDB is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
        http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details. */

#pragma once
#include "execution_defs.h"
#include "execution_manager.h"
#include "executor_abstract.h"
#include "index/ix.h"
#include "system/sm.h"

class UpdateExecutor : public AbstractExecutor {
private:
    TabMeta tab_;
    std::vector<Condition> conds_;
    RmFileHandle* fh_;
    std::vector<Rid> rids_;
    std::string tab_name_;
    std::vector<SetClause> set_clauses_;
    SmManager* sm_manager_;

public:
    UpdateExecutor(SmManager* sm_manager, const std::string& tab_name, std::vector<SetClause> set_clauses,
        std::vector<Condition> conds, std::vector<Rid> rids, Context* context) {
        sm_manager_ = sm_manager;
        tab_name_ = tab_name;
        set_clauses_ = set_clauses;
        tab_ = sm_manager_->db_.get_table(tab_name);
        fh_ = sm_manager_->fhs_.at(tab_name).get();
        conds_ = conds;
        rids_ = rids;
        context_ = context;
    }
    std::unique_ptr<RmRecord> Next() override {
        //若是类型不匹配，可以做类型的兼容性转换
        for (auto& single_set : set_clauses_)
        {
            auto& lcol = *tab_.get_col(single_set.lhs.col_name);
            if (lcol.type == TYPE_FLOAT && single_set.rhs.type == TYPE_INT) {
                single_set.rhs.type = TYPE_FLOAT;
                single_set.rhs.float_val = single_set.rhs.int_val;
            }
            else if (lcol.type == TYPE_BIGINT && single_set.rhs.type == TYPE_INT) {
                single_set.rhs.type = TYPE_BIGINT;
                single_set.rhs.bigInt_val = single_set.rhs.int_val;
            }
            else if (lcol.type == TYPE_STRING && single_set.rhs.type == TYPE_TIME) {
                single_set.rhs.type = TYPE_STRING;
                single_set.rhs.str_val = single_set.rhs.time_val;
            }
            else if (lcol.type != single_set.rhs.type)
            {
                throw IncompatibleTypeError(coltype2str(lcol.type), coltype2str(single_set.rhs.type));
            }
            //若右边不是表达式，可以直接初始化右侧值
            if (!single_set.is_expr)
                single_set.rhs.init_raw(lcol.len);
        }

        for (auto& single_rid : rids_)
        {
            auto p_src_record = fh_->get_record(single_rid, context_);
            RmRecord src_record = *p_src_record;

            for (auto& single_set : set_clauses_)
            {
                auto& lcol = *tab_.get_col(single_set.lhs.col_name);
                //由于修改的common的setclause 若是表达式 需重新计算右值
                if (single_set.is_expr) {
                    std::shared_ptr<RmRecord> p_new_record = std::make_shared<RmRecord>(lcol.len);
                    if (single_set.rhs.type == TYPE_INT) {
                        *(int*)(p_new_record->data) = *reinterpret_cast<int*>(p_src_record->data + lcol.offset) + single_set.rhs.int_val;
                    }
                    else if (single_set.rhs.type == TYPE_BIGINT) {
                        *(long long*)(p_new_record->data) = *reinterpret_cast<long long*>(p_src_record->data + lcol.offset) + single_set.rhs.bigInt_val;
                    }
                    else if (single_set.rhs.type == TYPE_FLOAT) {
                        *(float*)(p_new_record->data) = *reinterpret_cast<float*>(p_src_record->data + lcol.offset) + single_set.rhs.float_val;
                    }
                    memcpy(p_src_record->data + lcol.offset, p_new_record->data, lcol.len);

                }
                else {//不为表达式 直接复制
                    memcpy(p_src_record->data + lcol.offset, single_set.rhs.raw->data, lcol.len);
                }

            }
            fh_->update_record(single_rid, p_src_record->data, context_);
        }

        return nullptr;
    }
    std::string getType() override {
        return "UpdateExecutor";
    }


    Rid& rid() override { return _abstract_rid; }
};